package fr.univ.colloque.dao;

import fr.univ.colloque.data.Colloque;
import fr.univ.colloque.data.Etat;
import fr.univ.colloque.data.Expose;
import fr.univ.colloque.data.Membre;
import fr.univ.colloque.data.MotCle;
import fr.univ.colloque.data.Notation;
import fr.univ.colloque.data.Personne;
import fr.univ.colloque.util.PoolConnexion;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Christophe
 */
public class ExposeDao
{

    /**
     * Récupère un exposé par rapport à son identifiant
     * 
     * @param id identifiant de l'exposé
     * @param avecMotCle true si on veut alimenter la liste des mots clés de l'exposé , false sinon
     * @param avecEvaluateur true si on veut récupérer les évaluateurs de l'exposé , false sinon
     * 
     * @return l'exposé ayant pour identifiant id
     */
    public Expose get(int id, boolean avecMotCle, boolean avecEvaluateur)
    {
        PoolConnexion pool = PoolConnexion.getInstance();

        String requete = "select * from EXPOSE where id_exp=?";

        String requeteEval = "select id_pers from GERER Where id_exp=?";
        PreparedStatement pStat = null;

        Connection con = null;
        ResultSet rs = null;

        Expose e = null;

        try
        {
            con = pool.getConnexion();
            pStat = con.prepareStatement(requete);
            pStat.setInt(1, id);
            rs = pStat.executeQuery();

            if (rs.next())
            {
                String titre = rs.getString("titre");
                String resume = rs.getString("resume");
                int idAuteur = rs.getInt("id_pers");
                int etat = rs.getInt("etat");

                PersonneDao pDao = new PersonneDao();
                Personne auteur = pDao.get(idAuteur);

                int idColloc = rs.getInt("id_colloc");
                ColloqueDao cDao = new ColloqueDao();
                Colloque c = cDao.get(idColloc, false);

                MotCleDao mCleDao = new MotCleDao();
                List<MotCle> lstMotCle = null;

                if (avecMotCle)
                {
                    // on récupère les mots clés de cet exposé
                    lstMotCle = mCleDao.getExposeMc(id);
                }

                e = new Expose(id, titre, resume, c, auteur, lstMotCle, Etat.get(etat));

                if (avecEvaluateur)
                {
                    // on récupère les évaluateurs affectés à la notation de cet exposé
                    
                    pStat = con.prepareStatement(requeteEval);
                    pStat.setInt(1, id);
                    rs = pStat.executeQuery();

                    for (int i = 0; rs.next(); i++)
                    {
                        int idPers = rs.getInt("id_pers");

                        Membre p = pDao.getEvalById(idPers);

                        if (i == 0)
                        {
                            e.setEvaluateur1(p);
                        }
                        else if (i == 1)
                        {
                            e.setEvaluateur2(p);
                        }
                    }
                }
            }
        }
        catch (SQLException ex)
        {
            Logger.getLogger(PersonneDao.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally
        {
            pool.fermerConnexion(rs, pStat, con);
        }

        return e;
    }

    /**
     * 
     * @param co
     * @return 
     */
    public boolean isEvaluer(Colloque co)
    {
        PoolConnexion pool = PoolConnexion.getInstance();

        String requete = "select count(g.id_exp) 'nb_exp' FROM EXPOSE e ,GERER g where  g.id_exp = e.id_exp and id_colloc=?";
        PreparedStatement pStat = null;

        Connection con = null;
        ResultSet rs = null;

        boolean evaluer = false;

        try
        {
            con = pool.getConnexion();
            pStat = con.prepareStatement(requete);
            pStat.setInt(1, co.getId());
            rs = pStat.executeQuery();

            if (rs.next())
            {
                int nb = rs.getInt("nb_exp");

                if (nb > 0)
                {
                    evaluer = true;
                }
            }

        }
        catch (SQLException ex)
        {
            Logger.getLogger(PersonneDao.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally
        {
            pool.fermerConnexion(rs, pStat, con);
        }

        return evaluer;
    }

    /**
     * Récupère les exposés d'un colloque et leurs affecte des évaluateurs si ils n'en ont pas.
     * 
     * @param co
     * @return 
     */
    public List<Expose> getExposesColloque(Colloque co)
    {
        PoolConnexion pool = PoolConnexion.getInstance();

        String requete = "select e.*, g.id_pers as 'eval' FROM EXPOSE e LEFT JOIN GERER g ON g.id_exp = e.id_exp where id_colloc=?";
        PreparedStatement pStat = null;

        Connection con = null;
        ResultSet rs = null;

        Expose e = null;

        boolean dejaEvaluer = isEvaluer(co);

        Map<Integer, Expose> mapExpose = new HashMap<Integer, Expose>();
        List<Integer> listIdEvalAffecte = new ArrayList<Integer>();
        PersonneDao pDao = new PersonneDao();
        try
        {
            con = pool.getConnexion();
            pStat = con.prepareStatement(requete);
            pStat.setInt(1, co.getId());
            rs = pStat.executeQuery();

            while (rs.next())
            {
                int id = rs.getInt("id_exp");
                String titre = rs.getString("titre");
                String resume = rs.getString("resume");
                int idAuteur = rs.getInt("id_pers");
                int etat = rs.getInt("etat");

                MotCleDao mCleDao = new MotCleDao();
                List<MotCle> lstMotCle = null;
                lstMotCle = mCleDao.getExposeMc(id);

                String idEvalStr = rs.getString("eval");

                Personne auteur = pDao.get(idAuteur);

                Membre evaluateur = null;

                if (idEvalStr != null)
                {
                    int idEval = Integer.parseInt(idEvalStr);
                    evaluateur = pDao.getEvalById(idEval);
                    listIdEvalAffecte.add(evaluateur.getId());
                }
                else
                {
                    evaluateur = pDao.trouverEvaluateur(lstMotCle, listIdEvalAffecte, auteur.getInstitution().getId());
                    if (evaluateur != null)
                    {
                        listIdEvalAffecte.add(evaluateur.getId());

                        if (dejaEvaluer)
                        {
                            pDao.ajouterEvaluateur(evaluateur.getId(), id);
                        }
                    }
                }

                if (mapExpose.containsKey(id))
                {
                    // L'exposé a deja ete ajouté donc on ne fait qu'ajouter le deuxième eval
                    e = mapExpose.get(id);
                    e.setEvaluateur2(evaluateur);
                }
                else
                {
                    // Expose pas encore ajouté à la map 
                    e = new Expose(id, titre, resume, co, auteur, lstMotCle, Etat.get(etat));
                    e.setEvaluateur1(evaluateur);
                    mapExpose.put(id, e);
                }
            }

            // On essaie d'affecter le deuxième évaluateur pour les exposés qui en ont pas.
            for (Map.Entry<Integer, Expose> entry : mapExpose.entrySet())
            {
                Expose exp = entry.getValue();

                if (exp.getEvaluateur2() == null)
                {
                    Membre eval2 = pDao.trouverEvaluateur(exp.getLstMc(), listIdEvalAffecte, exp.getPersonne().getId());

                    if (eval2 != null)
                    {
                        exp.setEvaluateur2(eval2);
                        listIdEvalAffecte.add(eval2.getId());

                        if (dejaEvaluer)
                        {
                            pDao.ajouterEvaluateur(eval2.getId(), exp.getId());
                        }
                    }

                }
            }

        }
        catch (SQLException ex)
        {
            Logger.getLogger(PersonneDao.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally
        {
            pool.fermerConnexion(rs, pStat, con);
        }

        return new ArrayList<Expose>(mapExpose.values());
    }

    /**
     * Récupère les exposés d'un candidat
     * 
     * @param candidat 
     * @return 
     */
    public List<Expose> getExposeCandidat(Personne candidat)
    {
        PoolConnexion pool = PoolConnexion.getInstance();

        String requete = "select * from EXPOSE where id_pers=?";
        PreparedStatement pStat = null;

        Connection con = null;
        ResultSet rs = null;

        List<Expose> lExp = new ArrayList<Expose>();

        try
        {
            con = pool.getConnexion();
            pStat = con.prepareStatement(requete);
            pStat.setInt(1, candidat.getId());
            rs = pStat.executeQuery();

            while (rs.next())
            {
                String titre = rs.getString("titre");
                String resume = rs.getString("resume");
                int id = rs.getInt("id_exp");
                int etat = rs.getInt("etat");

                int idColloc = rs.getInt("id_colloc");
                ColloqueDao cDao = new ColloqueDao();
                Colloque c = cDao.get(idColloc, false);

                List<MotCle> lstMotCle = null;

                Expose e = new Expose(id, titre, resume, c, candidat, lstMotCle, Etat.get(etat));

                lExp.add(e);
            }

        }
        catch (SQLException ex)
        {
            Logger.getLogger(PersonneDao.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally
        {
            pool.fermerConnexion(rs, pStat, con);
        }

        return lExp;
    }

    /**
     * Enregistre l'exposé en bdd
     * 
     * @param expose exposé à enregistrer
     * 
     * @return l'identifiant de l'exposé venant d'être enregistré
     */
    public Integer save(Expose expose)
    {
        String requete = "insert into EXPOSE (titre, resume, id_pers,id_colloc) values (?,?,?,?)";

        PoolConnexion pool = PoolConnexion.getInstance();

        PreparedStatement pStat = null;
        ResultSet rs = null;

        Connection con = null;

        Integer id = null;

        try
        {
            con = pool.getConnexion();
            pStat = con.prepareStatement(requete, Statement.RETURN_GENERATED_KEYS);
            pStat.setString(1, expose.getLibelle());
            pStat.setString(2, expose.getResume());
            pStat.setInt(3, expose.getPersonne().getId());
            pStat.setInt(4, expose.getColloc().getId());

            pStat.executeUpdate();

            rs = pStat.getGeneratedKeys();

            if (rs.next())
            {
                id = rs.getInt(1);
            }

        }
        catch (SQLException ex)
        {
            Logger.getLogger(PersonneDao.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally
        {
            pool.fermerConnexion(rs, pStat, con);
        }

        return id;
    }
    
    /**
     * Mise à jour de l'état d'un exposé
     * 
     * @param pExpose Exposé à mettre à jour
     */
    public void majEtat(Expose pExpose)
    {
        String requete = "update EXPOSE set etat=? where id_exp=?";

        PoolConnexion pool = PoolConnexion.getInstance();

        PreparedStatement pStat = null;
        ResultSet rs = null;

        Connection con = null;

        Integer id = null;

        try
        {
            con = pool.getConnexion();
            pStat = con.prepareStatement(requete);
            pStat.setInt(1, pExpose.getEtat().getId());
            pStat.setInt(2, pExpose.getId());

            pStat.executeUpdate();

        }
        catch (SQLException ex)
        {
            Logger.getLogger(PersonneDao.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally
        {
            pool.fermerConnexion(rs, pStat, con);
        }
    }

    /**
     * Récupère les exposés et leur notation pour un évaluateur
     * 
     * @param idEval identifiant de l'évaluateur
     * 
     * @return une Map avec pour key l'Exposé et pour valeur les Notation faite par l'evaluateur
     */
    public Map<Expose, Notation> getExpoEvaluer(int idEval)
    {
        PoolConnexion pool = PoolConnexion.getInstance();

        String requete = "select e.*, g.pertinence, g.importance, g.lisibilite, g.decisionFinale from EXPOSE e , GERER g where e.id_exp=g.id_exp and g.id_pers=?";
        PreparedStatement pStat = null;

        Connection con = null;
        ResultSet rs = null;

        Map<Expose, Notation> mapExpNote = new HashMap<Expose, Notation>();

        try
        {
            con = pool.getConnexion();
            pStat = con.prepareStatement(requete);
            pStat.setInt(1, idEval);
            rs = pStat.executeQuery();

            while (rs.next())
            {
                String titre = rs.getString("titre");
                String resume = rs.getString("resume");
                int idAuteur = rs.getInt("id_pers");
                int id = rs.getInt("id_exp");
                int etat = rs.getInt("etat");

                int nImp = rs.getInt("importance");
                int nLis = rs.getInt("lisibilite");
                int nDec = rs.getInt("decisionFinale");
                int nPert = rs.getInt("pertinence");

                PersonneDao pDao = new PersonneDao();
                Personne auteur = pDao.get(idAuteur);

                //   Personne eval = pDao.get(idEval);

                int idColloc = rs.getInt("id_colloc");
                ColloqueDao cDao = new ColloqueDao();
                Colloque c = cDao.get(idColloc, false);

                MotCleDao mCleDao = new MotCleDao();
                List<MotCle> lstMotCle = null;

                lstMotCle = mCleDao.getExposeMc(id);

                Expose e = new Expose(id, titre, resume, c, auteur, lstMotCle, Etat.get(etat));
                Notation n = new Notation(nPert, nImp, nLis, nDec);

                mapExpNote.put(e, n);
            }

        }
        catch (SQLException ex)
        {
            Logger.getLogger(PersonneDao.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally
        {
            pool.fermerConnexion(rs, pStat, con);
        }

        return mapExpNote;
    }

    /**
     * Récupère les notes d'un exposé et d'un évaluateur
     * 
     * @param pIdExp identifiant de l'exposé
     * @param pIdEval identifiant de l'evaluateur
     * @return 
     */
    public Notation getNote(int pIdExp, int pIdEval)
    {
        PoolConnexion pool = PoolConnexion.getInstance();

        String requete = "select g.pertinence, g.importance, g.lisibilite, g.decisionFinale from GERER g where g.id_exp=? and g.id_pers=?";
        PreparedStatement pStat = null;

        Connection con = null;
        ResultSet rs = null;

        Notation n = null;

        try
        {
            con = pool.getConnexion();
            pStat = con.prepareStatement(requete);
            pStat.setInt(1, pIdExp);
            pStat.setInt(2, pIdEval);

            rs = pStat.executeQuery();

            if (rs.next())
            {
                int nImp = rs.getInt("importance");
                int nLis = rs.getInt("lisibilite");
                int nDec = rs.getInt("decisionFinale");
                int nPert = rs.getInt("pertinence");

                n = new Notation(nPert, nImp, nLis, nDec);
            }

        }
        catch (SQLException ex)
        {
            Logger.getLogger(PersonneDao.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally
        {
            pool.fermerConnexion(rs, pStat, con);
        }

        return n;
    }

    /**
     * Enregistre les notes d'un exposé faites par un évaluateur en bdd
     * 
     * @param idExp identifiant de l'exposé
     * @param idEval identifiant de l'évaluateur
     * @param nImp note sur le critère "Importance"
     * @param nPert note sur le critère "Pertinence"
     * @param nLis note sur le critère "Lisibilité"
     * @param nDec note sur le critère "Décision"
     */
    public void enregistrerNote(int idExp, int idEval, int nImp, int nPert, int nLis, int nDec)
    {
        String requete = "update GERER set pertinence=?, importance=?, lisibilite=?, decisionFinale=? where id_pers=? and id_exp=?";

        PoolConnexion pool = PoolConnexion.getInstance();

        PreparedStatement pStat = null;
        ResultSet rs = null;

        Connection con = null;

        try
        {
            con = pool.getConnexion();
            pStat = con.prepareStatement(requete);
            pStat.setInt(1, nPert);
            pStat.setInt(2, nImp);
            pStat.setInt(3, nLis);
            pStat.setInt(4, nDec);
            pStat.setInt(5, idEval);
            pStat.setInt(6, idExp);

            pStat.executeUpdate();
        }
        catch (SQLException ex)
        {
            Logger.getLogger(PersonneDao.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally
        {
            pool.fermerConnexion(rs, pStat, con);
        }
    }
}
